#include "Util.h"
#include <Poco\Logger.h>
#include "Poco\Util\LayeredConfiguration.h"
#include "Poco\RecursiveDirectoryIterator.h"
#include <Poco\File.h>
#include <Poco\Path.h>
#include <Poco\Exception.h>
#include <Poco\FileStream.h>
#include <string>
#include <Poco\Util\Application.h>
#include "Cryptoer.h"

using std::string;
using Poco::Path;
using Poco::File;
using Poco::FileInputStream;
using Poco::FileOutputStream;
//using Poco::SimpleRecursiveDirectoryIterator;
using Poco::SiblingsFirstRecursiveDirectoryIterator;

 Poco::Util::Application *Util::_app;
 Poco::Logger *Util::_logger;
 Poco::Util::LayeredConfiguration *Util::_config;
 std::string& Util::_srcPathName=std::string();
 std::string& Util::_srcsPathName = std::string();
 Path& Util::_srcPath=Path();
 Path& Util::_srcsPath=Path();
 Cryptoer * Util::_cryptoer;

Util::Util()
{
}


Util::~Util()
{
}

void Util::init(Poco::Util::Application & app, Cryptoer *pcryptoer)
{

	Util::_app = &app;
	Util::_logger = &app.logger();
	Util::_config = &app.config();
	Util::_srcPath = (Path().absolute().pushDirectory(_config->getString("src")));
	Util::_srcsPath = (Path().absolute().pushDirectory(_config->getString("srcs")));
	Util::_srcPathName = (_srcPath.toString());
	Util::_srcsPathName = (_srcsPath.toString());
	Util::_cryptoer = pcryptoer;
}
std::string Util::readContents(const File& file) {
	return readContents(file.path());
}
std::string Util::readDirContents(const Poco::File & file, std::vector<FSplitterInfo>& infos)
{
	std::string pathname = file.path();
	SiblingsFirstRecursiveDirectoryIterator targetit(file);
	SiblingsFirstRecursiveDirectoryIterator tend;
	string res;
	for (; targetit != tend; ++targetit) {
		if (targetit->isFile()) {
			FSplitterInfo fi;
			fi.beginPos = res.length();
			res.append(Util::readContents(*targetit));
			fi.endPos = res.length();
			fi.lastModify = targetit->getLastModified().epochTime();
			fi.filepath = targetit->path().substr(pathname.length());
			infos.push_back(fi);
		}
	}
	return res;

}
std::string Util::readContents(const std::string & fname)
{
	FileInputStream fis(fname);
	std::string str((std::istreambuf_iterator<char>(fis)), std::istreambuf_iterator<char>());
	fis.close();
	return str;
}
void Util::writeContents(const Poco::File & file, const std::string & contents)
{
	Path p = Path(file.path());
	File odir(p.parent());
	if (!odir.exists())
		odir.createDirectories();
	FileOutputStream fos(file.path());
	fos << contents;
	fos.close();

}
void Util::writeContents(const std::string& outpathname, const std::string& contents) {
	Path p = Path(outpathname);
	File odir(p.parent());
	if (!odir.exists())
		odir.createDirectories();
	FileOutputStream fos(outpathname);
	fos << contents;
	fos.close();
}
std::string Util::getSrcsFileName(const std::string & fn)
{
	std::string fntmp = fn;
	return fntmp.replace(0, _srcPathName.length(), _srcsPathName);
}
std::string Util::getSrcFileName(const std::string & fn)
{
	std::string fntmp = fn;
	return fntmp.replace(0, _srcsPathName.length(), _srcPathName);
}

Poco::File Util::getSrcsFile(const std::string & fn)
{
	return Poco::File(getSrcsFileName(fn));
}

Poco::File Util::getSrcFile(const std::string & fn)
{
	return Poco::File(getSrcFileName(fn));
}

Poco::File Util::getSrcsFile(const Poco::File & f)
{
	return getSrcsFile(f.path());
}

Poco::File Util::getSrcFile(const Poco::File & f)
{
	return getSrcFile(f.path());
}

Poco::Path Util::getBackupPath()
{
	//Path backPath(Path().absolute().pushDirectory(app.config().getString("backup-dir", "backup")));
	if (!_app->config().has("backup-dir")) {
		throw Poco::IllegalStateException("'backup-dir' must be set,please check property file.");
	}
	return Path(_app->config().getString("backup-root", "e:\\SRC_BACKUP"),
		_app->config().getString("backup-dir")).makeDirectory();
}

Cryptoer * Util::getCurrentCryptoer()
{
	return Util::_cryptoer;
}

void Util::listDirFiles(const std::string & path, std::vector<File>& files)
{
	SiblingsFirstRecursiveDirectoryIterator targetit(path);
	SiblingsFirstRecursiveDirectoryIterator tend;
	string res;
	for (; targetit != tend; ++targetit) {
		if (targetit->isFile()) {
			files.push_back(File(*targetit));
		}
	}
}

void Util::listDirs(const std::string & path, std::vector<Poco::File>& files)
{
	SiblingsFirstRecursiveDirectoryIterator targetit(path);
	SiblingsFirstRecursiveDirectoryIterator tend;
	string res;
	for (; targetit != tend; ++targetit) {
		if (targetit->isDirectory()) {
			files.push_back(File(*targetit));
		}
	}
}
void Util::listDirs(const std::string & path, std::vector<Poco::Path>& files)
{
	SiblingsFirstRecursiveDirectoryIterator targetit(path);
	SiblingsFirstRecursiveDirectoryIterator tend;
	string res;
	for (; targetit != tend; ++targetit) {
		if (targetit->isDirectory()) {
			files.push_back(Path(targetit->path()));
		}
	}
}
void Util::listDirWithFiles(const std::string & path, std::vector<Poco::File>& files)
{
	SiblingsFirstRecursiveDirectoryIterator targetit(path);
	SiblingsFirstRecursiveDirectoryIterator tend;
	string res;
	for (; targetit != tend; ++targetit) {
			files.push_back(File(*targetit));
	}
}

Poco::Path Util::getRelativePath(Poco::Path & base, Poco::Path& absolute)
{
	base.makeDirectory();
	if (absolute.getDevice() != base.getDevice()) {
		throw new Poco::IllegalStateException("absolute is not a child of base");
	}
	for (int i = 0; i < base.depth(); i++) {
		if (base[i] != absolute[i]) {
			throw new Poco::IllegalStateException("absolute is not a child of base");
		}
	}
      Poco::Path res;
	  for (int i = base.depth(); i < absolute.depth(); i++)
		  res.pushDirectory(absolute[i]);
	  if(!absolute.getFileName().empty())
		res.setFileName(absolute.getFileName());
	  return res;
}
